package top.dotgo.web.base.aspect;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ClassUtil;
import cn.hutool.core.util.ReflectUtil;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.context.annotation.Configuration;
import top.dotgo.kit.ContextKit;
import top.dotgo.kit.bean.AccInfoBean;
import top.dotgo.model.BaseQuery;
import top.dotgo.model.IBaseBean;
import top.dotgo.model.IBaseEntity;
import top.dotgo.web.base.annotations.IgnoreFill;

import java.lang.reflect.Field;

/**
 * @author jornl
 * @date 2020/3/24 0:47 星期二
 */
@Aspect
@Configuration
@Slf4j
public class AutoFillDataAspect {

    public static final String CREATE_TIME = "createTime";
    public static final String CREATE_BY = "createBy";
    public static final String TOP_COMPANY_ID = "topCompanyId";
    public static final String COMPANY_ID = "companyId";
    public static final String DEPARTMENT_ID = "departmentId";
    public static final String SORT = "sort";
    public static final String EDIT_TIME = "editTime";
    public static final String EDIT_BY = "editBy";
    public static final String DEL_TIME = "delTime";
    public static final String DEL_BY = "delBy";
    public static final String DESC = "desc";

    /**
     * 列表方法 切点
     */
    @Pointcut("execution(* top.dotgo.web..list*(..))")
    public void listCut() {

    }

    /**
     * 新增方法 切点
     */
    @Pointcut("execution(* top.dotgo.web..create(..))")
    public void createCut() {
    }

    /**
     * 修改方法 切点
     */
    @Pointcut("execution(* top.dotgo.web..edit(..))")
    public void editCut() {
    }

    /**
     * 删除方法 切点
     */
    @Pointcut("execution(* top.dotgo.web..del(..))")
    public void delCut() {
    }

    /**
     * list方法时 填充数据
     *
     * @param joinPoint joinPoint
     */
    @Before("listCut()")
    public void listHandler(JoinPoint joinPoint) {
        Object bean = getBean(joinPoint);
        if (bean == null) {
            return;
        }
        //降序排序 sort
        fillValue(bean, DESC, SORT);

        //降序排序 createTime
        fillValue(bean, DESC, CREATE_TIME);

        //过滤 删除过的数据
        fillValue(bean, DEL_BY, "nu:1");

        //如果 标记忽略
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        if (signature != null) {
            IgnoreFill ignoreFill = signature.getMethod().getAnnotation(IgnoreFill.class);
            if (ignoreFill != null && ignoreFill.list()) {
                return;
            }
        }

        AccInfoBean infoBean = ContextKit.getAccInfo();
        //降序排序 COMPANY_ID
        fillValue(bean, COMPANY_ID, infoBean.getCompanyId());

    }

    /**
     * create方法时 填充数据
     *
     * @param joinPoint joinPoint
     */
    @Before("createCut()")
    public void createHandler(JoinPoint joinPoint) {
        Object bean = getBean(joinPoint);
        if (bean == null) {
            return;
        }

        AccInfoBean infoBean = ContextKit.getAccInfo();
        //填充 createTime
        fillValue(bean, CREATE_TIME, DateUtil.date());
        //填充 createBy
        fillValue(bean, CREATE_BY, infoBean.getUserId() != null ? infoBean.getUserId() : infoBean.getAccId());
        //填充 topCompany
        fillValue(bean, TOP_COMPANY_ID, infoBean.getTopCompanyId());
        //填充 companyId
        fillValue(bean, COMPANY_ID, infoBean.getCompanyId());
        //填充 departmentId
        fillValue(bean, DEPARTMENT_ID, infoBean.getDepId());

        //填充 sort
        fillValue(bean, SORT, 0);

    }

    /**
     * edit方法时 填充数据
     *
     * @param joinPoint joinPoint
     */
    @Before("editCut()")
    public void editHandler(JoinPoint joinPoint) {
        Object bean = getBean(joinPoint);
        if (bean == null) {
            return;
        }
        AccInfoBean infoBean = ContextKit.getAccInfo();
        //填充 editTime
        fillValue(bean, EDIT_TIME, DateUtil.date());
        //填充 editBy
        fillValue(bean, EDIT_BY, infoBean.getUserId() != null ? infoBean.getUserId() : infoBean.getAccId());
    }

    /**
     * del方法时 填充数据
     *
     * @param joinPoint joinPoint
     */
    @Before("delCut()")
    public void delHandler(JoinPoint joinPoint) {
        Object bean = getBean(joinPoint);
        if (bean == null) {
            return;
        }
        AccInfoBean infoBean = ContextKit.getAccInfo();
        //填充 editTime
        fillValue(bean, DEL_TIME, DateUtil.date());
        //填充 editBy
        fillValue(bean, DEL_BY, infoBean.getUserId() != null ? infoBean.getUserId() : infoBean.getAccId());
    }

    /**
     * 根据 切面参数 获取 IBaseBean
     *
     * @param joinPoint joinPoint
     * @return IBaseBean
     */
    private Object getBean(JoinPoint joinPoint) {
        Object[] args = joinPoint.getArgs();
        Object bean = null;
        for (Object arg : args) {
            if (arg instanceof IBaseBean || arg instanceof IBaseEntity || arg instanceof BaseQuery) {
                bean = arg;
                break;
            }
        }
        return bean;
    }

    /**
     * 填充值
     *
     * @param bean      bean
     * @param fieldName fieldName
     * @param value     value
     */
    private void fillValue(Object bean, String fieldName, Object value) {
        Field field = ClassUtil.getDeclaredField(bean.getClass(), fieldName);
        if (field == null) {
            field = ClassUtil.getDeclaredField(bean.getClass().getSuperclass(), fieldName);
        }
        if (field == null) {
            return;
        }

        field.setAccessible(true);
        Object val = ReflectUtil.getFieldValue(bean, field);
        if (val == null) {
            ReflectUtil.setFieldValue(bean, field, value);
        }
    }

}
